void setFileName(void) {
  // Forms Sequential File Names, storing sequence number in EEPROM
  unsigned int fileNum = (int(EEPROM.read(1)) << 8) + EEPROM.read(0);
  
  fileName = "Log" + String(fileNum) + ".txt";
  
  EEPROM.write(1, byte((++fileNum >> 8) & 0xFF));
  EEPROM.write(0, byte(fileNum & 0xFF));
}

// ******************************************************************
// I2C receiveHandler
void receiveHandler(int numBytes) {
  // Processes I2C Command & Any Associated Data Bytes
  i2cCmd = Wire.read();
  switch (i2cCmd) {
    case _WRITE_LOG :
    {
      for (int i = 1; i < numBytes; i++) {
        byte inByte = Wire.read();
        if (fileOpen) logFile.write(inByte);
      }
      break;
    }
    case _OPEN :
    {
      if (haveSD) {
        if (needFileName) setFileName();
        char fname[13];
        unsigned int len = fileName.length();
        fileName.toCharArray(fname, len + 1);
        logFile = SD.open(fname, FILE_WRITE);
        needFileName = true;
        timeTagged = false;
        fileOpen = true;
        logStatus |= 0x06;
      }
      break;
    }
    case _CLOSE :
    {
      if (fileOpen) logFile.close();
      fileOpen = false;
      logStatus &= 0xFD;
      break;
    }
    case _FNAME :
    {
      fileName = "";
      while (Wire.available()) {
        fileName += Wire.read();
      }
      if (fileName.length() > 0) {
        needFileName = false;
        logStatus &= 0xFB;
      break;
      }
    }
    case _LOG :
    {
      autoLog = Wire.read() != 0;
      byte m = 0x10;
      if (autoLog) {
        logStatus |= m;
      } else {
        logStatus &= !m;
      }
    }
    case _RESET :
    {
      if (numBytes == 3) {
        EEPROM.write(0, Wire.read());
        EEPROM.write(1, Wire.read());
      }
    }
    case _MINLOG :
    {
      if (numBytes == 3) minLogTime = int(Wire.read()) + (int(Wire.read()) << 8);
    }
    case _PLAT :
    {
      if (numBytes == 2) {
        byte mdl = Wire.read();
        gps.setMode(mdl);
      }
    }
  }
  while (Wire.available()) Wire.read();
}

// ******************************************************************
// I2C requestHandler
void requestHandler(void) {
  // Queues Requested Bytes in I2C Write Buffer
  switch (i2cCmd) {
    case _POS :
    {
      Wire.write(gps.position.b, 12);
      break;
    }
    /* case _VEL :
    {
      Wire.write(gps.velocity.b, 12);
      break;
    } */
    case _AGE :
    {
      union u {
        byte b[4];
        long age;
      } t;
      t.age = gps.gps_age();
      Wire.write(t.b, 4);
      break;
    }
    case _STATUS :
    {
      Wire.write(gps.status);
      break;
    }
    case _LOGSTAT :
    {
      Wire.write(logStatus);
      break;
    }
  }
}
